package com.tenement.service.impl;

import cn.hutool.core.stream.CollectorUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.tenement.common.GlobalException;
import com.tenement.entity.Menu;
import com.tenement.enums.RespBusiness;
import com.tenement.mapper.MenuMapper;
import com.tenement.service.MenuService;
import com.tenement.service.RoleMenuService;
import com.tenement.vo.QueryVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.tenement.entity.table.MenuTableDef.MENU;

/**
 *  服务层实现。
 *
 * @author BertXie
 * @since 1.0.1
 */
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final MenuMapper menuMapper;

    private final RoleMenuService roleMenuService;

    @Override
    public int operator(Menu menu) {
        return menuMapper.insertOrUpdateSelective(menu);
    }

    @Override
    public Page<Menu> list(QueryVo queryVo) {
        QueryWrapper queryWrapper = QueryWrapper.create().from(MENU).where(MENU.MENU_NAME
                .like(queryVo.getKeyWord(), StrUtil.isNotEmpty(queryVo.getKeyWord()))
                .or(MENU.NAME.like(queryVo.getKeyWord(), StrUtil.isNotEmpty(queryVo.getKeyWord())))
                .or(MENU.REMARK.like(queryVo.getKeyWord(), StrUtil.isNotEmpty(queryVo.getKeyWord())))
        ).and(MENU.STATUS.eq(queryVo.getStatus(), queryVo.getStatus() != -1))
                .orderBy(MENU.SORT_ORDER,false).orderBy(MENU.UPDATE_TIME,false);
        Page<Menu> data = menuMapper.paginate(queryVo.getPage(), queryVo.getSize(), queryWrapper);
        if(data.getTotalRow() >= 1) {
            List<Menu> records = data.getRecords();
            List<Menu> topLevelMenus = records.stream()
                    .filter(menu -> menu.getPId() == 0 || records.stream().noneMatch(other -> other.getId().equals(menu.getPId())))
                    .peek(menu -> menu.setChildren(getChildren(menu, records)))
                    .collect(Collectors.toList());
            data.setRecords(topLevelMenus);
            return data;
        }
        return new Page<>();
    }


    @Override
    public List<Menu> treeNode(String keyWord) {
        List<Menu> menus = menuMapper.selectListByQuery(QueryWrapper.create().from(MENU)
                .where(MENU.MENU_NAME.like(keyWord, StrUtil.isNotEmpty(keyWord))
                        .or(MENU.NAME.like(keyWord, StrUtil.isNotEmpty(keyWord)))
                        .or(MENU.REMARK.like(keyWord, StrUtil.isNotEmpty(keyWord))))
        );

        // 如果没有顶级菜单，我们将所有一级菜单项作为顶级菜单处理
        List<Menu> topLevelMenus = menus.stream()
                .filter(menu -> menu.getPId() == 0 || menus.stream().noneMatch(other -> other.getId().equals(menu.getPId())))
                .peek(menu -> menu.setChildren(getChildren(menu, menus)))
                .collect(Collectors.toList());
        return topLevelMenus;
    }


    /*
     * 递归获取子菜单
     *
     * @param menu
     * @param menus
     * @return
     */
    private List<Menu> getChildren(Menu menu, List<Menu> menus) {
        return menus.stream()
                .filter(child -> child.getPId().equals(menu.getId()))
                .peek(child -> child.setChildren(getChildren(child, menus)))
                .collect(Collectors.toList());
    }


    @Override
    public List<Menu> roleMenu(Long roleId) {
        List<Long> menuIds = roleMenuService.menuIds(roleId);
        if (ObjectUtil.isNotEmpty(menuIds)) {
            return menuMapper.selectListByQuery(QueryWrapper.create().from(MENU).where(MENU.ID.in(menuIds)));
        }
        return new ArrayList<>();
    }


    @Transactional
    @Override
    public int delete(Long id) {
        QueryWrapper countWrapper = QueryWrapper.create().from(MENU).where(MENU.P_ID.eq(id));
        long lowerLevelCount = menuMapper.selectCountByQuery(countWrapper);
        if (lowerLevelCount == 0) {
            int rows = menuMapper.deleteById(id);
            roleMenuService.removeByMenuId(id);
            return rows;
        }
        throw new GlobalException(RespBusiness.CANNOT_DELETE_WITH_CHILDREN);
    }

    @Override
    public List<Menu> userRoleMenus(List<Long> menuIds) {
        return menuMapper.selectListByQuery(QueryWrapper.create().from(MENU).where(MENU.ID.in(menuIds)));
    }


}
